package com.example.ribbonserver;

import com.example.ribbonserver.hystrix.HelloGetCommand;
import com.example.ribbonserver.hystrix.HelloService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * 前面说过在微服务架构中, 各个服务之间通常是基于HTTP的Restful API进行通信,
 *
 * Spring Cloud有两种服务调用方式，一种是Ribbon+RestTemplate，另一种是Feign
 *
 * Ribbon是一个客户端负载均衡器，它可以很好地控制HTTP和TCP客户端的行为
 *
 * @author zhanghaidong
 */
////@EnableHystrix
@RestController
//@EnableEurekaClient
//@SpringBootApplication
@SpringCloudApplication
public class RibbonServerApplication {

    private static final Logger logger = LoggerFactory.getLogger(RibbonServerApplication.class);

    public static void main(String[] args) {
        SpringApplication.run(RibbonServerApplication.class, args);
    }

    @LoadBalanced
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    @Autowired
    private HelloService helloService;

    /**
     * 可能大家发现我之前是通过ip地址和端口号进行调用, 现在不再手动获取ip和端口，而是直接通过服务名称调用现在改为服务名进行调用了,
     * 因为通过Ribbon和Eureka结合使用时从Eureka注册中心中获取服务端列表从而获取到服务名所对应的ip以及端口号
     *
     *
     * 发生熔断时 会调用我们自定义的异常方法 则执行fallback
     * @param name
     * @return
     */
    @HystrixCommand(fallbackMethod = "helloErr",
            commandProperties = {@HystrixProperty(name = "execution.isolation.strategy", value = "THREAD")},
            threadPoolProperties = {
                @HystrixProperty(name = "coreSize", value = "20")
            }
    )
    @RequestMapping(value = "/hello")
    public String hello(String name){
        return this.restTemplate().getForObject("http://EUREKA-CLIENT/hello?name=" + name, String.class);
    }

    @RequestMapping(value = "/helloV")
    public String helloV(String name){
        logger.info("-------------helloV:"+name);
        return helloService.get(name);
    }

    @RequestMapping(value = "/helloV2")
    public String helloCommand(String name){
        //为了测试这么写
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        logger.info("-------------helloV2:"+name);
        HelloGetCommand helloGetCommand = new HelloGetCommand(restTemplate(), name);

        //同步调用
        return helloGetCommand.execute();
    }

    public String helloErr(String name){
        return "服务异常，请稍后再试 Hystrix";
    }

}
